View Javadoc

1   /*
2    * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted under the terms of either of the following
6    * Open Source licenses:
7    *
8    * The GNU General Public License, version 2, or any later version, as
9    * published by the Free Software Foundation
10   * (http://www.fsf.org/copyleft/gpl.html);
11   *
12   *  or
13   *
14   * The Semiotek Public License (http://webmacro.org/LICENSE.)
15   *
16   * This software is provided "as is", with NO WARRANTY, not even the
17   * implied warranties of fitness to purpose, or merchantability. You
18   * assume all risks and liabilities associated with its use.
19   *
20   * See www.webmacro.org for more information on the WebMacro project.
21   */
22  
23  package org.webmacro.util;
24  
25  import org.webmacro.*;
26  import org.webmacro.servlet.*;
27  import org.webmacro.engine.*;
28  
29  
30  import javax.servlet.Servlet;
31  import javax.servlet.ServletException;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  import java.io.FileOutputStream;
35  import java.io.InputStream;
36  import java.io.InputStreamReader;
37  import java.io.OutputStream;
38  
39  
40  /***
41   * WMEval encapsulates an instance of WebMacro for reuse in any java application.
42   * <p>
43   * Its main benefit are a number of convenience methods for evaluating a template
44   * and directing output either to a supplied output stream or to a file.
45   * <p>
46   * It can parse a single template stream and then evaluate that template
47   * over a number of different contexts. And, it can maintain a single context
48   * and evaluate different templates over the same context. Each time a context
49   * or a template is provided, it is retained as state.
50   * <p>
51   * The context can therefore be preserved over multiple "writes" of different
52   * templates.
53   * <p>
54   * The template stream can be any text stream but is often a rule stream containing
55   * wm script directives.
56   * <p>
57   * This helper class is useful for evaluating WebMacro templates for which
58   * flexibility in managing the evaluation options is key.
59   * @author Lane Sharman
60   * @version 3.0
61   */
62  public class WMEval
63  {
64  
65      //-------public members-----
66  
67      //-------private and protected members-----
68      private WebMacro wm;
69      private Log log;
70      private Template currentTemplate;
71      private OutputStream out = System.out;
72      private Context context;
73      /***
74       * If an output file is not specified as an argument, it
75       * must be found in the context under this key.
76       */
77      public static final String outputContextKey = "OutputFileName";
78  
79      //-------constructor(s)-----
80    /***
81     * The constructor for WebMacro decorator in a servlet context.
82     */
83    public WMEval (Servlet servlet)
84    {
85        // Build a web macro environment for currentTemplate execution.
86        try
87        {
88            if (servlet == null)
89                wm = new WM();
90            else
91                wm = new WM(servlet);
92            context = wm.getContext();
93            log = wm.getBroker().getBrokerLog();
94        }
95        catch (Exception e)
96        {
97            e.printStackTrace(System.err);
98            throw new IllegalStateException(e.toString());
99        }
100   }
101 
102     public WMEval ()
103     {
104       // Build a web macro environment for currentTemplate execution.
105       try
106       {
107           wm = new WM();
108           context = wm.getContext();
109       }
110       catch (Exception e)
111       {
112           e.printStackTrace(System.err);
113           throw new IllegalStateException(e.toString());
114       }
115     }
116     
117     /***
118      * Return the settings associated with this WebMacro instance.
119      */
120     public Settings getSettings()
121     {
122       return wm.getBroker().getSettings();
123     }
124     
125     /***
126      * Return the log associated with this instance of WMEval.
127      */
128     public Log getLog()
129     {
130     	return this.log;
131     }
132 
133 
134     //-------public initializers/destroyers-----
135     /***
136      * Initializes WMEval so that it can perform currentTemplate evaluation
137      * on multiple contexts. Init parses the currentTemplate supplied.
138      * <p>
139      * The argument to init() is the currentTemplate as a stream allowing the currentTemplate
140      * to come from pretty much anywhere such as a url, a file, or a db field.
141      * <p>
142      * Care must be given to the fact that in parsing the currentTemplate, th current vm is able
143      * to resolve locations of other currentTemplates referenced within the supplied currentTemplate.
144      * <p>
145      * Note, once this is complete, the parsed currentTemplate can be applied to successive
146      * new object contexts. In other words, the application context
147      * can assert new objects for currentTemplate application and remove others.
148      * @param template The stream containing the top-level, unparsed currentTemplate.
149      *
150      */
151     public Template init (InputStream template) throws Exception
152     {
153         //
154         Template t = new StreamTemplate(wm.getBroker(), new InputStreamReader(template));
155         t.parse();
156         this.currentTemplate = t;
157         return t;
158     }
159     
160 
161     public void error (String msg, Exception e)
162     {
163         wm.getLog("ERROR").error(msg, e);
164     }
165 
166     /***
167      * Provides for a new context to be established.
168      */
169     public Context getNewContext ()
170     {
171         Context c = wm.getContext();
172         this.context = c;
173         return c;
174     }
175 
176     public WebContext getNewContext (HttpServletRequest req, HttpServletResponse resp)
177     {
178         WebContext c = wm.getWebContext(req, resp);
179         this.context = c;
180         return c;
181     }
182 
183     /***
184      * Gets the current context.
185      */
186     public Context getCurrentContext ()
187     {
188         return this.context;
189     }
190 
191     /***
192      * Gets the current template.
193      */
194     public Template getCurrentTemplate()
195     {
196         return this.currentTemplate;
197     }
198 
199     /***
200      * A convenience method to find and parse a template in the local template path.
201      */
202     public Template parseLocalTemplate (String templateName) throws Exception
203     {
204         Template t = wm.getTemplate(templateName);
205         this.currentTemplate = t;
206         return t;
207     }
208 
209     /***
210      * Supplies the parsed currentTemplate directly.
211      * @param parsedTemplate The currentTemplate parsed possibly from a previous run.
212      */
213     public void setCurrentTemplate (Template parsedTemplate)
214     {
215         this.currentTemplate = parsedTemplate;
216     }
217 
218     /***
219      * Supplies a context to be  parsed currentTemplate directly.
220      * @param c The context to be used for the evaluation.
221      */
222     public void setCurrentContext (Context c)
223     {
224         this.context = c;
225     }
226 
227     /***
228      * Sets the output stream to be different than the default, System.out.
229      * @param out The new output stream for any output during currentTemplate evaluation.
230      */
231     public void setOutputStream (OutputStream out)
232     {
233         this.out = out;
234     }
235 
236     /***
237      * Evaluates the context of this instance and the instance's
238      * current template and current output stream using UTF8.
239      */
240     public void eval() throws Exception
241     {
242       eval(context, currentTemplate);
243     }
244 
245 
246     /***
247      * Evaluate the context supplied against the current template.
248      * @param context The WebMacro context.
249      */
250     public String eval (Context context) throws Exception
251     {
252       return eval(context, currentTemplate);
253     }
254 
255     /***
256      * Evaluates the string template against the current context
257      * and returns the value. If an output stream is specified, the value
258      * is written out as well to this stream.
259      * @param templateName The name of the template.
260      * @param out An optional output stream.
261      * @return The output from the evaluated template
262      */
263     public String eval (Context context, String templateName, OutputStream out) throws Exception
264     {
265       return eval(context, templateName, out, null);
266     }
267 
268     /***
269      * Evaluates the string template against the current context
270      * and returns the value.
271      * @param templateName The name of the template.
272      * @return The output from the evaluated template
273      */
274     public String eval (String templateName) throws Exception
275     {
276         return eval(context, templateName, null, null);
277     }
278 
279     /***
280      * Evaluates the string template against a new context and writes
281      * it to the http Response output stream using the proper encoding.
282      * <p>
283      * This is an exceptionally useful method for a servlet to use to
284      * write out a template.
285      * <p>
286      * @param context The WM context to use.
287      * @param templateName The name of the template.
288      * @param resp The servlet response from which the encoding will be derived.
289      * @return The output from the evaluated template.
290      */
291     public String eval (WebContext context, String templateName,
292                       HttpServletResponse resp) throws ServletException
293     {
294       String value = null;
295       try
296       {
297           resp.setContentType("text/html");
298           String encoding = wm.getConfig(WMConstants.TEMPLATE_OUTPUT_ENCODING);
299           if (encoding == null)
300           {
301               encoding = resp.getCharacterEncoding();
302           }
303           value = eval(context, templateName, resp.getOutputStream(), encoding);
304       }
305       catch (Exception e)
306       {
307           e.printStackTrace(System.err);
308           throw new ServletException(e.toString());
309       }
310       return value;
311     }
312 
313     /***
314      * Evaluate the supplied context and template and return the result as a
315      * as a string.
316      */
317     public String eval (Context context, Template template) throws Exception
318     {
319         return template.evaluateAsString(context);
320     }
321 
322     /***
323      * Evaluates the context using a file template sending the output to a disk file.
324      * <p>
325      * This method is the preferred method when an output stream is to be written
326      * as well as the value of the string is to be returned.
327      * @param context The context to use.
328      * @param templateName The input template file in the resource path.
329      * @param out The output stream. If null, an attempt will be
330      * made to locate the outputstream in the context using the output stream key if
331      * in the context. If no output stream can be resolved, the method does not
332      * throw an exception.
333      * @param encoding If null, the platform's encoding will be used.
334      * @return The output from the evaluation of the template.
335      */
336     public String eval (Context context, String templateName,
337                         OutputStream out, String encoding) throws Exception
338     {
339       Template t = wm.getTemplate(templateName);
340       String value = t.evaluateAsString(context);
341       // output the file
342       if (out == null) 
343       {
344         String outputFileName = (String) context.get(outputContextKey);
345         if (outputFileName != null)
346         {
347           out = new FileOutputStream(outputFileName);
348         }
349       }
350       if (out != null) // write it to out
351       {
352         if (encoding == null)
353         {
354           out.write(value.getBytes());
355         }
356         else {
357           out.write(value.getBytes(encoding));
358         }
359         out.close();
360       }
361       this.currentTemplate = t;
362       this.context = context;
363       return value;
364     }
365 
366     /***
367      *  Evaluates the current context for the input file and writes it to the output file.
368      */
369     public String eval (Context context, String templateName, String outputFileName, boolean append, String encoding) throws Exception
370     {
371       OutputStream out = new FileOutputStream(outputFileName, append);
372       return eval(context, templateName, out, encoding);
373     }      
374 
375 
376     /***
377      * Free up resources when no longer needed.
378      */
379     public void destroy ()
380     {
381         wm = null;
382         currentTemplate = null;
383     }
384 }